import json
import logging

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
from django.views.decorators.http import require_POST

from .forms import CodeFileForm, CodeForm, MultiFileUploadForm
from .models import Code
from accounts.models import FeatureSwitch

logger = logging.getLogger(__name__)


def check_code_operations_enabled(request):
    """检查代码操作功能是否启用"""
    if not FeatureSwitch.is_feature_enabled('code_operations'):
        disabled_message = FeatureSwitch.get_disabled_message('code_operations')

        # 检查是否是AJAX请求
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or 'application/json' in request.headers.get('Accept', ''):
            return JsonResponse({'success': False, 'error': disabled_message}, status=403)
        else:
            messages.error(request, disabled_message)
            return redirect('home')
    return None


@login_required
@ensure_csrf_cookie
def code_list(request):
    """显示用户的代码列表"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    codes = Code.objects.filter(user=request.user)

    # 分页处理
    paginator = Paginator(codes, 10)  # 每页显示10条
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    return render(request, 'codes/code_list.html', {
        'page_obj': page_obj,
        'code_operations_enabled': FeatureSwitch.is_feature_enabled('code_operations'),
    })


@login_required
def code_detail(request, code_id):
    """重定向到文件管理页面"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    return redirect('codes:code_files', code_id=code_id)


@login_required
def code_create(request):
    """创建新代码项目"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    if request.method == 'POST':
        form = CodeForm(request.POST)
        if form.is_valid():
            # 保存代码基本信息
            code = form.save(commit=False)
            code.user = request.user
            code.save()

            messages.success(request, '代码项目创建成功！请上传项目文件。')
            return redirect('codes:upload_files', code_id=code.id)
    else:
        form = CodeForm()

    return render(request, 'codes/code_create.html', {'form': form})


@login_required
def code_update(request, code_id):
    """更新代码信息"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    if request.method == 'POST':
        form = CodeForm(request.POST, instance=code)

        if form.is_valid():
            form.save()
            messages.success(request, '代码信息更新成功！')
            return redirect('codes:code_detail', code_id=code.id)
    else:
        form = CodeForm(instance=code)

    return render(request, 'codes/code_form.html', {'form': form, 'code': code, 'action': '更新'})


@login_required
def code_delete(request, code_id):
    """软删除代码"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    if request.method == 'POST':
        code.soft_delete()  # 使用软删除而不是物理删除
        messages.success(request, '代码删除成功！历史战报数据已保留。')
        return redirect('codes:code_list')

    return render(request, 'codes/code_confirm_delete.html', {'code': code})


@login_required
@require_POST
def toggle_public(request, code_id):
    """切换代码的公开状态"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or 'application/json' in request.headers.get('Accept', ''):
            return JsonResponse({'success': False, 'error': '管理员账号不能使用代码管理功能。'}, status=403)
        else:
            messages.error(request, '管理员账号不能使用代码管理功能。')
            return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    # 检查是否是AJAX请求
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or 'application/json' in request.headers.get('Accept', ''):
        try:
            # 获取新的状态值
            is_public = request.POST.get('is_public') == 'true'
            code.is_public = is_public
            code.save()

            status = '公开' if code.is_public else '私有'
            return JsonResponse(
                {
                    'success': True,
                    'message': f'代码状态已设置为{status}！',
                    'is_public': code.is_public,
                }
            )
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)}, status=400)
    else:
        # 传统的表单提交处理
        code.is_public = not code.is_public
        code.save()

        status = '公开' if code.is_public else '私有'
        messages.success(request, f'代码状态已设置为{status}！')

        return redirect('codes:code_detail', code_id=code.id)


@login_required
@require_POST
def toggle_starred(request, code_id):
    """切换代码的星标状态"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or 'application/json' in request.headers.get('Accept', ''):
            return JsonResponse({'success': False, 'error': '管理员账号不能使用代码管理功能。'}, status=403)
        else:
            messages.error(request, '管理员账号不能使用代码管理功能。')
            return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    # 检查是否是AJAX请求
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or 'application/json' in request.headers.get('Accept', ''):
        try:
            # 获取新的状态值
            is_starred = request.POST.get('is_starred') == 'true'
            code.is_starred = is_starred
            code.save()  # save方法会自动处理只能有一个星标的逻辑

            status = '星标' if code.is_starred else '取消星标'
            return JsonResponse(
                {
                    'success': True,
                    'message': f'代码已{status}！',
                    'is_starred': code.is_starred,
                }
            )
        except Exception as e:
            return JsonResponse({'success': False, 'error': str(e)}, status=400)
    else:
        # 传统的表单提交处理
        code.is_starred = not code.is_starred
        code.save()

        status = '星标' if code.is_starred else '取消星标'
        messages.success(request, f'代码已{status}！')

        return redirect('codes:code_detail', code_id=code.id)


# 多文件管理视图
@login_required
def code_files_view(request, code_id):
    """多文件项目管理页面"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    code = get_object_or_404(Code, id=code_id, user=request.user)
    files = code.files.all().order_by('file_path')

    context = {
        'code': code,
        'files': files,
        'file_tree': code.get_file_tree(),
        'main_file': code.get_main_file(),
        'total_size': code.get_total_size(),
        'code_operations_enabled': FeatureSwitch.is_feature_enabled('code_operations'),
    }
    return render(request, 'codes/code_files.html', context)


@login_required
def upload_files(request, code_id):
    """文件上传处理"""
    import logging

    logger = logging.getLogger(__name__)

    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    if request.method == 'POST':
        logger.info(f'收到文件上传请求，FILES: {list(request.FILES.keys())}')
        form = MultiFileUploadForm(request.POST, request.FILES)

        if form.is_valid():
            try:
                # 处理上传的文件
                created_files = form.process_files(code)
                logger.info(f'成功上传 {len(created_files)} 个文件')

                messages.success(request, f'成功上传 {len(created_files)} 个文件！')
                return redirect('codes:code_files', code_id=code.id)
            except Exception as e:
                logger.error(f'文件处理失败: {str(e)}')
                messages.error(request, f'文件上传失败: {str(e)}')
        else:
            logger.error(f'表单验证失败: {form.errors}')
            for field, errors in form.errors.items():
                for error in errors:
                    messages.error(request, f'{field}: {error}')
    else:
        form = MultiFileUploadForm()

    return render(request, 'codes/upload_files.html', {'form': form, 'code': code})


@login_required
def edit_file(request, code_id, file_id=None):
    """编辑单个文件"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)

    if file_id:
        file_obj = get_object_or_404(code.files, id=file_id)
        action = '编辑'
    else:
        file_obj = None
        action = '创建'

    if request.method == 'POST':
        form = CodeFileForm(request.POST, instance=file_obj)
        if form.is_valid():
            file_instance = form.save(commit=False)
            file_instance.code = code

            # 检查文件路径唯一性
            existing = code.files.filter(file_path=file_instance.file_path)
            if file_obj:
                existing = existing.exclude(id=file_obj.id)

            if existing.exists():
                form.add_error('file_path', '该文件路径已存在')
            else:
                # 如果设置为主文件，清除其他主文件标记
                if file_instance.is_main:
                    code.files.filter(is_main=True).update(is_main=False)

                file_instance.save()
                messages.success(request, f'文件{action}成功！')
                return redirect('codes:code_files', code_id=code.id)
    else:
        form = CodeFileForm(instance=file_obj)

    return render(
        request,
        'codes/edit_file.html',
        {'form': form, 'code': code, 'file_obj': file_obj, 'action': action},
    )


@login_required
def delete_file(request, code_id, file_id):
    """删除文件"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)
    file_obj = get_object_or_404(code.files, id=file_id)

    if request.method == 'POST':
        file_path = file_obj.file_path
        file_obj.delete()
        messages.success(request, f'文件 {file_path} 删除成功！')
        return redirect('codes:code_files', code_id=code.id)

    return render(request, 'codes/code_confirm_delete.html', {'code': code, 'file_obj': file_obj})


@login_required
def download_project(request, code_id):
    """下载整个项目为ZIP文件"""
    import io
    import zipfile

    from django.http import HttpResponse

    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        messages.error(request, '管理员账号不能使用代码管理功能。')
        return redirect('home')

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    code = get_object_or_404(Code, id=code_id, user=request.user)
    files = code.files.all()

    if not files.exists():
        messages.error(request, '项目中没有文件可下载')
        return redirect('codes:code_files', code_id=code.id)

    # 创建ZIP文件
    zip_buffer = io.BytesIO()
    with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
        for file_obj in files:
            zip_file.writestr(file_obj.file_path, file_obj.content)

    zip_buffer.seek(0)

    # 返回ZIP文件
    response = HttpResponse(zip_buffer.getvalue(), content_type='application/zip')
    response['Content-Disposition'] = f'attachment; filename="{code.title}.zip"'
    return response


@csrf_exempt
@require_POST
def api_file_content(request, code_id, file_id):
    """获取文件内容API"""
    try:
        # 检查用户是否已登录
        if not request.user.is_authenticated:
            return JsonResponse({'success': False, 'error': '请先登录'}, status=401)
        
        # 检查用户是否为管理员，如果是则拒绝访问
        if request.user.is_staff:
            return JsonResponse({'success': False, 'error': '管理员账号不能使用代码管理功能。'}, status=403)

        # 检查代码操作功能是否启用
        if not FeatureSwitch.is_feature_enabled('code_operations'):
            disabled_message = FeatureSwitch.get_disabled_message('code_operations')
            return JsonResponse({'success': False, 'error': disabled_message}, status=403)

        code = get_object_or_404(Code, id=code_id, user=request.user)
        file_obj = get_object_or_404(code.files, id=file_id)

        return JsonResponse(
            {
                'success': True,
                'content': file_obj.content,
                'file_path': file_obj.file_path,
                'file_name': file_obj.file_name,
                'is_main': file_obj.is_main,
                'file_size': file_obj.file_size,
            }
        )
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)}, status=500)


@login_required
@require_POST
def update_project_info(request, code_id):
    """更新代码项目信息（标题和描述）的API接口"""
    # 检查用户是否为管理员，如果是则拒绝访问
    if request.user.is_staff:
        return JsonResponse({'success': False, 'error': '管理员账号不能使用代码管理功能。'}, status=403)

    # 检查代码操作功能是否启用
    feature_check = check_code_operations_enabled(request)
    if feature_check:
        return feature_check

    try:
        # 获取代码对象
        code = get_object_or_404(Code, id=code_id, user=request.user)
        
        # 解析JSON请求体
        data = json.loads(request.body)
        new_title = data.get('title', '').strip()
        new_description = data.get('description', '').strip()
        
        # 验证标题不能为空
        if not new_title:
            return JsonResponse({'success': False, 'error': '项目标题不能为空'}, status=400)
        
        # 更新标题和描述
        code.title = new_title
        code.description = new_description
        code.save()
        
        logger.info(f'用户 {request.user.username} 更新了代码项目 {code.title} 的信息')
        
        return JsonResponse({
            'success': True,
            'message': '项目信息更新成功',
            'title': new_title,
            'description': new_description
        })
        
    except json.JSONDecodeError:
        return JsonResponse({'success': False, 'error': '无效的JSON数据'}, status=400)
    except Exception as e:
        logger.error(f'更新项目信息失败: {str(e)}')
        return JsonResponse({'success': False, 'error': '更新失败，请重试'}, status=500)
